package cc.mllt.demoaopmybatisauth.demos.web.interceptor;

import cc.mllt.demoaopmybatisauth.demos.web.annotation.PermissionRequired;
import cc.mllt.demoaopmybatisauth.demos.web.annotation.PermissionRequiredContainer;
import cc.mllt.demoaopmybatisauth.demos.web.model.dto.RuleQueryParam;
import cc.mllt.demoaopmybatisauth.demos.web.model.entity.DataPermissionRule;
import cc.mllt.demoaopmybatisauth.demos.web.service.CacheDataService;
import cc.mllt.demoaopmybatisauth.demos.web.service.DataPermissionRuleService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.*;

@Aspect
@Component
public class PermissionInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(PermissionInterceptor.class);

    @Autowired
    DataPermissionRuleService dataPermissionRuleService;

    @Autowired
    CacheDataService cacheDataService;

    /**
     * 环绕通知：拦截带有 @PermissionRequired 注解的方法
     */
    @Around("@annotation(cc.mllt.demoaopmybatisauth.demos.web.annotation.PermissionRequired) || " +
            "@annotation(cc.mllt.demoaopmybatisauth.demos.web.annotation.PermissionRequiredContainer)")
    public Object checkPermission(ProceedingJoinPoint joinPoint) throws Throwable {
        Method method = getMethodFromJoinPoint(joinPoint);

        // 获取所有 PermissionRequired 注解（包括单个和容器中的多个）
        List<PermissionRequired> permissions = getAllPermissionRequiredAnnotations(method);

        if (permissions.isEmpty()) {
            logger.warn("未找到任何权限注解，跳过权限检查");
            return joinPoint.proceed();
        }

        // 遍历所有权限注解并逐一检查
        for (PermissionRequired permissionRequired : permissions) {
            String module = permissionRequired.module();
            String operation = permissionRequired.operation();
            String requiredPermission = generatePermissionKey(module, operation).toLowerCase();

            logger.info("开始权限检查，所需权限: {}", requiredPermission);

            // 获取当前用户权限
            Set<String> userPermissions = getCurrentUserPermissions();
            logger.info("用户拥有的权限: {}", userPermissions);

            // 检查权限
            if (!hasPermission(userPermissions, requiredPermission)) {
                String errorMessage = String.format("拒绝访问。所需权限: %s", requiredPermission);
                logger.error(errorMessage);
                throw new RuntimeException(errorMessage);
            }

            logger.info("权限验证通过，允许执行操作: {}", requiredPermission);
        }

        return joinPoint.proceed();
    }

    /**
     * 从方法中获取所有 PermissionRequired 注解
     */
    private List<PermissionRequired> getAllPermissionRequiredAnnotations(Method method) {
        List<PermissionRequired> permissions = new ArrayList<>();

        // 检查是否直接有单个 PermissionRequired 注解
        if (method.isAnnotationPresent(PermissionRequired.class)) {
            permissions.add(method.getAnnotation(PermissionRequired.class));
        }

        // 检查是否有 PermissionRequiredContainer 容器注解
        if (method.isAnnotationPresent(PermissionRequiredContainer.class)) {
            PermissionRequiredContainer container = method.getAnnotation(PermissionRequiredContainer.class);
            permissions.addAll(Arrays.asList(container.value()));
        }

        return permissions;
    }

    /**
     * 从 JoinPoint 中提取目标方法
     */
    private Method getMethodFromJoinPoint(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        return signature.getMethod();
    }

    /**
     * 生成权限键（格式: 模块:操作）
     */
    private String generatePermissionKey(String module, String operation) {
        return String.format("%s:%s", module, operation);
    }

    /**
     * 检查用户是否拥有指定权限
     */
    private boolean hasPermission(Set<String> userPermissions, String requiredPermission) {
        // 统一转为大写处理
        String upperPermission = requiredPermission.toLowerCase();

        // 精确匹配直接返回
        if (userPermissions.contains(upperPermission)) {
            return true;
        }

        // 拆解请求权限的模块和操作
        String[] parts = upperPermission.split(":");
        if (parts.length != 2) {
            return false; // 非法权限格式
        }
        String reqModule = parts[0];
        String reqOperation = parts[1];

        // 检查模块级全操作权限（例如 user:all）
        boolean hasModuleWildcard = userPermissions.contains(reqModule + ":all");

        // 检查全局操作权限（例如 all:query）
        boolean hasGlobalOperation = userPermissions.contains("all:" + reqOperation);

        return hasModuleWildcard || hasGlobalOperation;
    }

    /**
     * 模拟获取当前用户权限（实际项目需替换为从安全上下文获取）
     */
    private Set<String> getCurrentUserPermissions() {
        // 模拟查询参数（实际应从安全上下文获取用户信息） todo
        String uid = "1";
        RuleQueryParam ruleQueryParam = new RuleQueryParam();
        ruleQueryParam.setRoleIds(List.of(uid));
        ruleQueryParam.setUid(uid);

        // 获取已排序的规则列表（权重大->小）
        List<DataPermissionRule> rules = dataPermissionRuleService.getRules(ruleQueryParam);

        Set<String> permissions = new LinkedHashSet<>(); // 保持添加顺序
        Set<String> processedModules = new HashSet<>();  // 已处理的模块
        Map<String, DataPermissionRule> dataScopeRules = new HashMap<>();

        for (DataPermissionRule rule : rules) {
            String module = rule.getModuleCode().toLowerCase();

            // 模块去重：仅处理首个出现的模块（权重最高）
            if (!processedModules.contains(module)) {
                processedModules.add(module);

                // 拆分权限项并标准化格式
                String[] operations = rule.getDataPermission().split(":");
                for (String op : operations) {
                    String permissionKey = module + ":" + op.toLowerCase();
                    permissions.add(permissionKey);
                }
                // 添加数据范围规则到数据规则列表
                DataPermissionRule dataScopeRule = new DataPermissionRule();
                dataScopeRule.setModuleCode(module);
                dataScopeRule.setDataScope(rule.getDataScope());
                dataScopeRule.setRuleSql(rule.getRuleSql()); // 如果有自定义SQL
                dataScopeRules.put(module, dataScopeRule);
            }
        }
        // 缓存数据规则列表，后续其他模块可以快速根据用户id和模块选择规则
        cacheDataService.cacheDataScopeRules(ruleQueryParam.getUid(), dataScopeRules);
        return Collections.unmodifiableSet(permissions);
    }
}